package com.javaxiaobear.base.common.utils;

import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.javaxiaobear.base.common.constant.Constants;
import com.javaxiaobear.base.common.constant.HttpStatus;
import com.javaxiaobear.base.common.exception.ServiceException;
import com.javaxiaobear.base.framework.security.LoginUser;
import com.javaxiaobear.module.system.domain.SysRole;
import com.javaxiaobear.module.system.domain.SysUser;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.PatternMatchUtils;

/**
 * 安全服务工具类
 *
 * @author javaxiaobear
 */
@Slf4j
public class SecurityUtils {

  /** 用户ID */
  public static Long getUserId() {
    try {
      return getLoginUser().getUserId();
    } catch (Exception e) {
      throw new ServiceException("获取用户ID异常", HttpStatus.UNAUTHORIZED);
    }
  }

  /** 获取部门ID */
  public static Long getDeptId() {
    try {
      return getLoginUser().getDeptId();
    } catch (Exception e) {
      throw new ServiceException("获取部门ID异常", HttpStatus.UNAUTHORIZED);
    }
  }

  /** 获取用户账户 */
  public static String getUsername() {
    try {
      return getLoginUser().getUsername();
    } catch (Exception e) {
      throw new ServiceException("获取用户账户异常", HttpStatus.UNAUTHORIZED);
    }
  }

  /** 获取用户 */
  public static LoginUser getLoginUser() {
    try {
      if (StpUtil.isLogin()) return (LoginUser) StpUtil.getSession().get(SaSession.USER);
    } catch (Exception e) {
      throw new ServiceException("获取用户信息异常", HttpStatus.UNAUTHORIZED);
    }
    throw new ServiceException("用户未登录", HttpStatus.UNAUTHORIZED);
  }

  /** 获取用户 */
  public static LoginUser getLoginUser(Object loginId) {
    try {
      if (StpUtil.isLogin())
        return (LoginUser) StpUtil.getSessionByLoginId(loginId).get(SaSession.USER);
    } catch (Exception e) {
      log.error("获取用户信息异常", e);
      throw new ServiceException("获取用户信息异常", HttpStatus.UNAUTHORIZED);
    }
    throw new ServiceException("用户未登录", HttpStatus.UNAUTHORIZED);
  }

  public static SysUser getUser() {
    var loginUser = getLoginUser();
    if (loginUser == null) {
      return null;
    }
    return loginUser.getUser();
  }

  /**
   * 生成BCryptPasswordEncoder密码
   *
   * @param password 密码
   * @return 加密字符串
   */
  public static String encryptPassword(String password) {
    return BCrypt.hashpw(password);
  }

  /**
   * 判断密码是否相同
   *
   * @param rawPassword 真实密码
   * @param encodedPassword 加密后字符
   * @return 结果
   */
  public static boolean matchesPassword(String rawPassword, String encodedPassword) {
    return BCrypt.checkpw(rawPassword, encodedPassword);
  }

  /**
   * 是否为管理员
   *
   * @param userId 用户ID
   * @return 结果
   */
  public static boolean isAdmin(Long userId) {
    return userId != null && 1L == userId;
  }

  /**
   * 验证用户是否具备某权限
   *
   * @param permission 权限字符串
   * @return 用户是否具备某权限
   */
  public static boolean hasPermi(String permission) {
    return hasPermi(getLoginUser().getPermissions(), permission);
  }

  /**
   * 判断是否包含权限
   *
   * @param authorities 权限列表
   * @param permission 权限字符串
   * @return 用户是否具备某权限
   */
  public static boolean hasPermi(Collection<String> authorities, String permission) {
    return authorities.stream()
        .filter(StringUtils::hasText)
        .anyMatch(
            x ->
                Constants.ALL_PERMISSION.equals(x) || PatternMatchUtils.simpleMatch(x, permission));
  }

  /**
   * 验证用户是否拥有某个角色
   *
   * @param role 角色标识
   * @return 用户是否具备某角色
   */
  public static boolean hasRole(String role) {
    List<SysRole> roleList = getLoginUser().getUser().getRoles();
    Collection<String> roles =
        roleList.stream().map(SysRole::getRoleKey).collect(Collectors.toSet());
    return hasRole(roles, role);
  }

  /**
   * 判断是否包含角色
   *
   * @param roles 角色列表
   * @param role 角色
   * @return 用户是否具备某角色权限
   */
  public static boolean hasRole(Collection<String> roles, String role) {
    return roles.stream()
        .filter(StringUtils::hasText)
        .anyMatch(x -> Constants.SUPER_ADMIN.equals(x) || PatternMatchUtils.simpleMatch(x, role));
  }

  public static List<String> getPermissions(Object loginId) {
    return ListUtil.toList(getLoginUser(loginId).getPermissions());
  }

  public static List<String> getRoles(Object loginId) {
    return ListUtil.toList(getLoginUser(loginId).getRoles());
  }

  public static void login(LoginUser user) {
    StpUtil.login(user.getUserId());
    StpUtil.getSession().set(SaSession.USER, user);
  }

  public static void setLoginUser(LoginUser user) {
    StpUtil.getSession().set(SaSession.USER, user);
  }
}
